8
高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。
具体而言,高阶组件是参数为组件,返回值为新组件的函数。
还不了解高阶组件的点这里

最近在做项目的时候遇到了一个情形:在系统后台存在多个全局设置开关,例如在多个页面都需要请求会员设置的开关。如果在每个需要调用全局设置的地方都去请求一下接口,就会有一种不优雅的感觉,这个时候我就想到利用高阶组件抽象一下。

版本一

getMemberSettingHoc = Component => class ContainerComponent extends React.Component {
    state = {
       loading: true,
       memberSetting: ''
    }
    componentDidMount() {
        Api.getSetting().then(memberSetting => {
            this.setState({ memberSetting })
        })
        ...doSomething
    }
    
    render() {
        return (
            <Component {...this.props} memberSetting={this.state.memberSetting} />
        )
    }
}

// 使用高阶组件
class Home extends Component {
   ...
}
export default getMemberSettingHoc(Home);

这个时候看起来编写一个 getMemberSettingHoc 的高阶组件可以让我们复用获取会员设置的逻辑

版本二

这个时候如果又多了几个全局开关,例如:交易设置,支付设置,预约设置...

问题来了,这个时候我们还需要编写更多的高阶组件来抽象这些设置吗?

答案是否定的,我们可以实现一个 preMountHoc 来处理这些请求,顾名思义, preMountHoc 就是在挂载之前做事情的高阶组件。

代码如下

const preMountDecorator = doSomething => ContentComponent => class PreMountComponent extends React.Component {

}

我们传入了一个参数,这个参数来传入要请求的接口 doList 和返回的字段 keyList ,在 PreMountComponent 挂载的时候去 doSomething, 然后通过props,传回给传入的 ContentComponent.

我们看下代码

// preMountHoc
const preMountHoc = doSomething => ContentComponent => class PreMountComponent extends React.Component {
    constructor() {
        super();

        this.state = {
            loading: true,
            result: {},
        };
    }

    componentDidMount() {
        const doList = get(doSomething, 'doList', []);
        const doListLength = get(doList, 'length') || 0;
        const keyList = get(doSomething, 'keyList', []);
        const keyListLength = get(keyList, 'length') || 0;
        if (doListLength == 0) {
            this.setState({ loading: false });
            return;
        }

        Promise.all(doList).then((res) => {
            const result = {};
            if (doListLength == keyListLength) {
                keyList.forEach((el, index) => {
                    result[el] = res[index];
                });
            } else {
                doList.forEach((el, index) => {
                    result[`pre_${index}`] = res[index];
                });
            }

            this.setState({ result, loading: false });
        });
    }

    render() {
        const { loading, result } = this.state;
        if (loading) {
            return <BlockLoading loading />;
        }

        return (
            <ContentComponent {...result} {...this.props} />
        );
    }
};

export default preMountHoc;

给 preMountHoc 传入的需要的请求和返回的字段名,就可以达到我们的目的,来看看使用方法

class ScrmList extends Component {
    ...
}

export default preMountHoc({
    doList: [settingApi.getPower(), settingApi.hasMemberThreshold()],
    keyList: ['memberStoreSetting', 'scrmConditionType'],
})(ScrmList)

当然高阶组件也是装饰器,你也可以这么用

@preMountHoc({
    doList: [settingApi.getPower(), settingApi.hasMemberThreshold()],
    keyList: ['memberStoreSetting', 'scrmConditionType'],
})
class ScrmList extends Component {
    ...
}

export default ScrmList;

总结

高阶组件并不是 React 的特性,是函数式编程的一种范式,最大的好处就是解耦和灵活性,在这分享下最近项目中的思考。


csywweb
232 声望8 粉丝

最担心的事不是写出ipcode,而是从不开始